"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.feedToCollection = exports.entryToBook = exports.adapter = void 0;
const opds_feed_parser_1 = require("opds-feed-parser");
let sanitizeHtml;
const createDOMPurify = require("dompurify");
if (typeof window === "undefined") {
  // sanitization needs to work server-side,
  // so we use jsdom to build it a window object
  const JSDOM = require("jsdom").JSDOM;
  const jsdom = new JSDOM("<!doctype html><html><body></body></html>", {
    url: "http://localhost",
    FetchExternalResources: false,
    ProcessExternalResources: false,
  });
  const window_1 = jsdom.window;
  const defaultView = window_1.defaultView;
  sanitizeHtml = createDOMPurify(defaultView).sanitize;
} else {
  sanitizeHtml = createDOMPurify(window).sanitize;
}
/** Converts OPDS data into the internal representation used by components. */
function adapter(data, url) {
  if (data instanceof opds_feed_parser_1.OPDSFeed) {
    // console.log('遍历OPDS解析器数据:',data)
    const collectionData = feedToCollection(data, url);
    return collectionData;
  } else if (data instanceof opds_feed_parser_1.OPDSEntry) {
    const bookData = entryToBook(data, url);
    return bookData;
  } else {
    throw "parsed data must be OPDSFeed or OPDSEntry";
  }
}
exports.adapter = adapter;
function entryToBook(entry, feedUrl) {
  const authors = entry.authors.map(function (author) {
    return author.name;
  });
  const contributors = entry.contributors.map(function (contributor) {
    return contributor.name;
  });
  let imageUrl, imageThumbLink;
  const artworkLinks = entry.links.filter(function (link) {
    return link instanceof opds_feed_parser_1.OPDSArtworkLink;
  });
  if (artworkLinks.length > 0) {
    imageThumbLink = artworkLinks.find(function (link) {
      return link.rel === "http://opds-spec.org/image/thumbnail";
    });
    if (imageThumbLink) {
      imageUrl = imageThumbLink.href;
    } else {
      console.log("WARNING: using possibly large image for " + entry.title);
      imageUrl = artworkLinks[0].href;
    }
  }
  let detailUrl;
  const detailLink = entry.links.find(function (link) {
    return link instanceof opds_feed_parser_1.CompleteEntryLink;
  });
  if (detailLink) {
    detailUrl = detailLink.href;
  }
  const categories = entry.categories
    .filter(function (category) {
      return !!category.label;
    })
    .map(function (category) {
      return category.label;
    });
  const openAccessLinks = entry.links
    .filter(function (link) {
      return (
        link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
        link.rel === opds_feed_parser_1.OPDSAcquisitionLink.OPEN_ACCESS_REL
      );
    })
    .map(function (link) {
      return {
        url: link.href,
        type: link.type,
      };
    });
  let borrowUrl;
  const borrowLink = entry.links.find(function (link) {
    return (
      link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
      link.rel === opds_feed_parser_1.OPDSAcquisitionLink.BORROW_REL
    );
  });
  if (borrowLink) {
    borrowUrl = borrowLink.href;
  }
  const allBorrowLinks = entry.links
    .filter(function (link) {
      return (
        link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
        link.rel === opds_feed_parser_1.OPDSAcquisitionLink.BORROW_REL
      );
    })
    .map(function (link) {
      let indirectType;
      const indirects = link.indirectAcquisitions;
      if (indirects && indirects.length > 0) {
        indirectType = indirects[0].type;
      }
      return {
        url: link.href,
        type: link.type,
        indirectType: indirectType,
      };
    });
  let fulfillmentType;
  const fulfillmentLinks = entry.links
    .filter(function (link) {
      return (
        link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
        link.rel === opds_feed_parser_1.OPDSAcquisitionLink.GENERIC_REL
      );
    })
    .map(function (link) {
      let indirectType;
      const indirects = link.indirectAcquisitions;
      if (indirects && indirects.length > 0) {
        indirectType = indirects[0].type;
      }
      return {
        url: link.href,
        type: link.type,
        indirectType: indirectType,
      };
    });
  let availability;
  let holds;
  let copies;
  const linkWithAvailability = entry.links.find(function (link) {
    return (
      link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
      !!link.availability
    );
  });
  if (linkWithAvailability) {
    (availability = linkWithAvailability.availability),
      (holds = linkWithAvailability.holds),
      (copies = linkWithAvailability.copies);
  }
  return {
    id: entry.id,
    licensepoolsId: entry.licensepoolsId,
    // licensepoolsId: "9527",
    title: entry.title,
    series: entry.series,
    authors: authors,
    contributors: contributors,
    subtitle: entry.subtitle,
    summary: entry.summary.content && sanitizeHtml(entry.summary.content),
    imageUrl: imageUrl,
    openAccessLinks: openAccessLinks,
    borrowUrl: borrowUrl,
    allBorrowLinks: allBorrowLinks,
    fulfillmentLinks: fulfillmentLinks,
    availability: availability,
    holds: holds,
    copies: copies,
    publisher: entry.publisher,
    issued: entry.issued,
    published: formatDate(entry.published),
    categories: categories,
    language: entry.language,
    url: detailUrl,
    raw: entry.unparsed,
  };
}
exports.entryToBook = entryToBook;
function entryToLink(entry, feedUrl) {
  const links = entry.links;
  if (links.length > 0) {
    const href = links[0].href;
    return {
      id: entry.id,
      text: entry.title,
      url: href,
    };
  }
  console.error(
    "Attempting to create Link with undefined url. entry is: ",
    entry
  );
  return null;
}
function dedupeBooks(books) {
  // using Map because it preserves key order
  const bookIndex = books.reduce(function (index, book) {
    index.set(book.id, book);
    return index;
  }, new Map());
  return Array.from(bookIndex.values());
}
function formatDate(inputDate) {
  const date = new Date(inputDate);
  const day = ("0" + date.getUTCDate()).slice(-2);
  const month = ("0" + (date.getUTCMonth() + 1)).slice(-2);
  const year = date.getUTCFullYear();
  return year + "-" + month + "-" + day;
}
function OPDSLinkToLinkData(feedUrl, link) {
  if (link === void 0) {
    link = null;
  }
  if (!link || !link.href) {
    return null;
  }
  return {
    url: link.href,
    text: link.title,
    type: link.rel,
  };
}
function feedToCollection(feed, feedUrl) {
  const collection = {
    id: feed.id,
    title: feed.title,
    url: feedUrl,
  };
  const books = [];
  const navigationLinks = [];
  let lanes = [];
  const laneTitles = [];
  const laneIndex = [];
  let facetGroups = [];
  let search = undefined;
  let nextPageUrl = undefined;
  let catalogRootLink;
  let parentLink;
  let shelfUrl = undefined;
  let links = [];
  feed.entries.forEach(function (entry) {
    if (feed instanceof opds_feed_parser_1.AcquisitionFeed) {
      // console.log('书本 opds entry',entry)
      const book = entryToBook(entry, feedUrl);
      const collectionLink = entry.links.find(function (link) {
        return link instanceof opds_feed_parser_1.OPDSCollectionLink;
      });
      if (collectionLink) {
        const title = collectionLink.title,
          href = collectionLink.href;
        if (laneIndex[title]) {
          laneIndex[title].books.push(book);
        } else {
          laneIndex[title] = {
            title: title,
            url: href,
            books: [book],
          };
          // use array of titles to preserve lane order
          laneTitles.push(title);
        }
      } else {
        books.push(book);
      }
    } else {
      const link = entryToLink(entry, feedUrl);
      if (link) navigationLinks.push(link);
    }
  });
  lanes = laneTitles.reduce(function (result, title) {
    const lane = laneIndex[title];
    lane.books = dedupeBooks(lane.books);
    result.push(lane);
    return result;
  }, lanes);
  let facetLinks = [];
  if (feed.links) {
    facetLinks = feed.links.filter(function (link) {
      return link instanceof opds_feed_parser_1.OPDSFacetLink;
    });
    const searchLink = feed.links.find(function (link) {
      return link instanceof opds_feed_parser_1.SearchLink;
    });
    if (searchLink) {
      search = { url: searchLink.href };
    }
    const nextPageLink = feed.links.find(function (link) {
      return link.rel === "next";
    });
    if (nextPageLink) {
      nextPageUrl = nextPageLink.href;
    }
    catalogRootLink = feed.links.find(function (link) {
      return link instanceof opds_feed_parser_1.OPDSCatalogRootLink;
    });
    parentLink = feed.links.find(function (link) {
      return link.rel === "up";
    });
    const shelfLink = feed.links.find(function (link) {
      return link instanceof opds_feed_parser_1.OPDSShelfLink;
    });
    if (shelfLink) {
      shelfUrl = shelfLink.href;
    }
    links = feed.links;
  }
  facetGroups = facetLinks.reduce(function (result, link) {
    const groupLabel = link.facetGroup;
    const label = link.title;
    const href = link.href;
    const active = link.activeFacet;
    const facet = { label: label, href: href, active: active };
    const newResult = [];
    let foundGroup = false;
    result.forEach(function (group) {
      if (group.label === groupLabel) {
        const facets = group.facets.concat(facet);
        newResult.push({ label: groupLabel, facets: facets });
        foundGroup = true;
      } else {
        newResult.push(group);
      }
    });
    if (!foundGroup) {
      const facets = [facet];
      newResult.push({ label: groupLabel, facets: facets });
    }
    return newResult;
  }, []);
  collection.lanes = lanes;
  collection.navigationLinks = navigationLinks;
  collection.books = dedupeBooks(books);
  collection.facetGroups = facetGroups;
  collection.search = search;
  collection.nextPageUrl = nextPageUrl;
  collection.catalogRootLink = OPDSLinkToLinkData(feedUrl, catalogRootLink);
  collection.parentLink = OPDSLinkToLinkData(feedUrl, parentLink);
  collection.shelfUrl = shelfUrl;
  function notNull(value) {
    return value !== null && value !== undefined;
  }
  collection.links = links
    .map(function (link) {
      return OPDSLinkToLinkData(feedUrl, link);
    })
    // we have to filter out the null values in order for typescript to accept this
    .filter(notNull);
  collection.raw = feed.unparsed;
  Object.freeze(collection);
  return collection;
}
exports.feedToCollection = feedToCollection;
